/**
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
             佛祖保佑       永无BUG
	佛曰:  
		写字楼里写字间，写字间里程序员；  
		程序人员写程序，又拿程序换酒钱。  
		酒醒只在网上坐，酒醉还来网下眠；  
		酒醉酒醒日复日，网上网下年复年。  
		但愿老死电脑间，不愿鞠躬老板前；  
		奔驰宝马贵者趣，公交自行程序员。  
		别人笑我忒疯癫，我笑自己命太贱；  
		不见满街漂亮妹，哪个归得程序员？
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

*/

package com.fclassroom.logger.service.sls;

import java.lang.management.ManagementFactory;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.aliyun.openservices.log.Client;
import com.aliyun.openservices.log.common.LogItem;
import com.aliyun.openservices.log.request.PutLogsRequest;
import com.fclassroom.logger.entity.LogCacheForSLS;
import com.jason.framework.util.DateUtil;
import com.jason.framework.util.StringUtil;
import com.jason.framework.util.SystemProperties;
import com.sun.management.OperatingSystemMXBean;

/**
 * @author Jason
 * @date 2016年4月23日 下午1:56:32 Copyright (c) 2016, email:14902300@qq.com All
 *       Rights Reserved.
 */
//@Service("logServiceForSLS")
public class LogServiceForSLSImpl implements ILogServiceForSLS, InitializingBean {
	protected static final Logger logger = LogManager.getLogger();
	private static Integer LOG_SIZE = 30;
	/**
	 * 阿里云日志服务相关配置
	 */
	private String project = SystemProperties.getProperties("ali.sls.project"); // 上面步骤创建的项目名称
	private String endpoint = SystemProperties.getProperties("ali.sls.endpoint"); // 选择与上面步骤创建
																					// project
	private String accessKeyId = SystemProperties.getProperties("ali.sls.accessKeyId");// 使用您的阿里云访问密钥
																						// AccessKeyId
	private String accessKeySecret = SystemProperties.getProperties("ali.sls.accessKeySecret"); // 使用您的阿里云访问密钥
	private Client slsClient;

	private String sls_family_student_logstore = "log_family_student";
	private String sls_family_student_topic_web = "log_family_student_web";
	private String sls_family_student_topic_app = "log_family_student_app";

	private String sls_family_parent_logstore = "log_family_parent";
	private String sls_family_parent_topic_wx = "log_family_parent_wx";

	private String sls_teacher_logstore = "log_teacher";
	private String sls_teacher_topic_web = "log_teacher_web";
	private String sls_teacher_topic_pc = "log_teacher_pc";
	private String sls_teacher_topic_app = "log_teacher_app";

	private String sls_report_logstore = "log_report";
	private String sls_report_topic_web = "log_report_web";

	// 正则提取日志的类型，拆解出不同的来源和topic
	private String regex = "useend:([^(|+})]*)";
	@Autowired
	private LogCacheForSLS logCacheForSLS;

	@SuppressWarnings("restriction")
	@Override
	public void afterPropertiesSet() throws Exception {
		/*暂时不使用队列方法，获取数据直接上传到sls*/
//		try {
//			slsClient = new Client(endpoint, accessKeyId, accessKeySecret);
//			logger.info("阿里云日志服务启动成功");
//		} catch (Exception e) {
//			logger.error("阿里云日志服务启动失败，" + e.getMessage());
//		}
//
//		MathContext mc = new MathContext(2, RoundingMode.HALF_DOWN);
//		OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
//		// 总的物理内存+虚拟内存
//		BigDecimal totalMemory = new BigDecimal(osmxb.getTotalPhysicalMemorySize());
//
//		Thread thread = new Thread(new Runnable() {
//			@Override
//			public void run() {
//				while (true) {
//					BigDecimal freeMemory = new BigDecimal(osmxb.getFreePhysicalMemorySize());
//					Float percent = freeMemory.divide(totalMemory, mc).floatValue();
//					if (percent >= 0.50) {
//						LOG_SIZE = 500;
//					} else if (percent >= 0.30 && percent < 0.50) {
//						LOG_SIZE = 300;
//					} else if (percent >= 0.15 && percent < 0.30) {
//						LOG_SIZE = 200;
//					} else {
//						LOG_SIZE = 100;
//					}
//					try {
//						Thread.sleep(30000);
//					} catch (InterruptedException e) {
//						logger.error("Thread.sleep(1000) fail:" + e.getMessage());
//					}
//				}
//			}
//		});
//		thread.setDaemon(true);
//		thread.start();
//
//		// LOG_SIZE = 3;
//		Vector<LogItem> logFamilyParentWX = new Vector<>();
//		Vector<LogItem> logFamilyStudentWEB = new Vector<>();
//		Vector<LogItem> logFamilyStudentAPP = new Vector<>();
//		Vector<LogItem> logReportWEB = new Vector<>();
//		Vector<LogItem> logTeacherPC = new Vector<>();
//		Vector<LogItem> logTeacherWEB = new Vector<>();
//		Vector<LogItem> logTeacherAPP = new Vector<>();
//
//		Thread operaterLogThread = new Thread(new Runnable() {
//			@Override
//			public void run() {
//				boolean teacherPCFlag = false;
//				boolean teacherWebFlag = false;
//				boolean teacherAppFlag = false;
//				boolean studentWebFlag = false;
//				boolean studentAppFlag = false;
//				boolean parentWxFlag = false;
//				boolean reportWebFlag = false;
//				while (true) {
//					teacherPCFlag = false;
//					teacherWebFlag = false;
//					teacherAppFlag = false;
//					studentWebFlag = false;
//					studentAppFlag = false;
//					parentWxFlag = false;
//					reportWebFlag = false;
//					try {
//						String logStr = logCacheForSLS.pullTeacherPCLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logTeacherPC.size() > 0) {
//								logger.info("直接提交list中数据。");
//								teacherPCFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logTeacherPC.add(log);
//						}
//						logStr = logCacheForSLS.pullTeacherWebLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logTeacherWEB.size() > 0) {
//								logger.info("直接提交list中数据。");
//								teacherWebFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logTeacherWEB.add(log);
//						}
//						logStr = logCacheForSLS.pullTeacherAppLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logTeacherAPP.size() > 0) {
//								logger.info("直接提交list中数据。");
//								teacherAppFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logTeacherAPP.add(log);
//						}
//
//						logStr = logCacheForSLS.pullStudentAppLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logFamilyStudentAPP.size() > 0) {
//								logger.info("直接提交list中数据。");
//								studentAppFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logFamilyStudentAPP.add(log);
//						}
//						logStr = logCacheForSLS.pullStudentWebLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logFamilyStudentWEB.size() > 0) {
//								logger.info("直接提交list中数据。");
//								studentWebFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logFamilyStudentWEB.add(log);
//						}
//						logStr = logCacheForSLS.pullParentWXLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logFamilyParentWX.size() > 0) {
//								logger.info("直接提交list中数据。");
//								parentWxFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logFamilyParentWX.add(log);
//						}
//						logStr = logCacheForSLS.pullReportWebLog();
//						if (null == logStr || StringUtil.isEmpty(logStr)) {
//							if (logReportWEB.size() > 0) {
//								logger.info("直接提交list中数据。");
//								reportWebFlag = true;// 当队列中无数据，但list集合中还有数据，此时应该把数据也提交到sls上，将flag设为true
//							}
//						} else {
//							LogItem log = new LogItem();
//							log.PushBack(DateUtil.getNow(DateUtil.YYYY_MM_DD_HH_MM_SS), logStr);
//							logReportWEB.add(log);
//						}
//					} catch (Exception e) {
//						// flag设为true，把list中数据直接提交到sls
//						teacherPCFlag = true;
//						teacherWebFlag = true;
//						teacherAppFlag = true;
//						studentWebFlag = true;
//						studentAppFlag = true;
//						parentWxFlag = true;
//						reportWebFlag = true;
//						e.printStackTrace();
//						logger.error("出错：" + e.getMessage());
//					}
//					if (logTeacherPC.size() >= LOG_SIZE || (logTeacherPC.size() > 0 && teacherPCFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_teacher_logstore,
//									sls_teacher_topic_pc, sls_teacher_topic_pc, logTeacherPC);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【{}】", logTeacherPC.size());
//							logTeacherPC.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logTeacherPC);
//						}
//					}
//					if (logTeacherWEB.size() >= LOG_SIZE || (logTeacherWEB.size() > 0 && teacherWebFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_teacher_logstore,
//									sls_teacher_topic_web, sls_teacher_topic_web, logTeacherWEB);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【" + logTeacherWEB.size() + "】,");
//							logTeacherWEB.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logTeacherWEB);
//						}
//					}
//					if (logTeacherAPP.size() >= LOG_SIZE || (logTeacherAPP.size() > 0 && teacherAppFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_teacher_logstore,
//									sls_teacher_topic_app, sls_teacher_topic_app, logTeacherAPP);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【" + logTeacherAPP.size() + "】,");
//							logTeacherAPP.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logTeacherAPP);
//						}
//					}
//
//					// 学生端
//					if (logFamilyStudentAPP.size() >= LOG_SIZE || (logFamilyStudentAPP.size() > 0 && studentAppFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_family_student_logstore,
//									sls_family_student_topic_app, sls_family_student_topic_app, logFamilyStudentAPP);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【" + logFamilyStudentAPP.size() + "】,");
//							logFamilyStudentAPP.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logFamilyStudentAPP);
//						}
//					}
//					if (logFamilyStudentWEB.size() >= LOG_SIZE || (logFamilyStudentWEB.size() > 0 && studentWebFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_family_student_logstore,
//									sls_family_student_topic_web, sls_family_student_topic_web, logFamilyStudentWEB);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【" + logFamilyStudentWEB.size() + "】,");
//							logFamilyStudentWEB.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logFamilyStudentWEB);
//						}
//					}
//
//					// 家长微信端
//					if (logFamilyParentWX.size() >= LOG_SIZE || (logFamilyParentWX.size() > 0 && parentWxFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_family_parent_logstore,
//									sls_family_parent_topic_wx, sls_family_parent_topic_wx, logFamilyParentWX);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【" + logFamilyParentWX.size() + "】,");
//							logFamilyParentWX.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logFamilyParentWX);
//						}
//					}
//
//					// 报表中心
//					if (logReportWEB.size() >= LOG_SIZE || (logReportWEB.size() > 0 && reportWebFlag)) {
//						try {
//							PutLogsRequest logReq = new PutLogsRequest(project, sls_report_logstore,
//									sls_report_topic_web, sls_report_topic_web, logReportWEB);
//							slsClient.PutLogs(logReq);
//							logger.info("成功上传数据，数据包大小：【{}】", logReportWEB.size());
//							logReportWEB.clear();
//						} catch (Exception e) {
//							// TODO: handle exception 如果日志失败，应该考虑再次修正。
//							handleException(e, logReportWEB);
//						}
//					}
//				}
//			}
//		});
//		operaterLogThread.setDaemon(true);
//		operaterLogThread.start();

	}

	/**
	 * 消费队列数据出错，回滚重新放回队列,并清除list中数据
	 * 
	 * @param e
	 * @param list
	 */
	private void handleException(Exception e, List<LogItem> list) {
		String mvalue = "";
		for (LogItem logItem : list) {
			mvalue = logItem.GetLogContents().get(0).GetValue();
			// 把数据放回到队列中
			logCacheForSLS.putLog(mvalue);
		}
		list.clear();// 清空list数据
		if (e == null || StringUtils.isEmpty(e.getMessage())) {
			return;
		}
		e.printStackTrace();
		logger.error("消费队列数据出错:" + e.getMessage());
	}
}
